//
//  ViewController.swift
//  Swift泛型
//
//  Created by yang on 2018/1/15.
//  Copyright © 2018年 YYY. All rights reserved.
//

import UIKit

protocol Container
{
    associatedtype itemType //声明一个关联类型
    mutating func appended(item: itemType)
    var count: Int{ get }
    subscript(i: Int) -> itemType { get }
}

extension Array :Container
{
    mutating internal func appended(item: Element) {}
}

class ViewController: UIViewController {

    override func viewDidLoad()
    {
        super.viewDidLoad()
        
        /*********************泛型函数*********************/
        // 使用appendIntToArray添加整形数组数据
        var arr = [2,5]
        appendArray(argu1: [100, 200], argu2: &arr)
        print(arr)
        
        let strAddr1 = ["Swift", "OC"]
        var strAddr2 = ["Java", "PHP"]
        appendArray(argu1: strAddr1, argu2: &strAddr2)
        print(strAddr2)
        
        //交换两个数
        var a = 66
        var b = 88
        
        print(a, b)
        swap(oneValue: &a, twoValue: &b)
        print("a = \(a)  b = \(b)")
        
        var str1 = "hello"
        var str2 = "china"
        swap(oneValue: &str1, twoValue: &str2)
        print("str1 = \(str1)  str2 = \(str2)")
        
        /*********************泛型版本的栈*********************/
        //入栈、出栈
        var stackOfStrings = Stack<String>()
        stackOfStrings.push(item: "hello")
        stackOfStrings.push(item: "world")
        stackOfStrings.push(item: "happy")
        stackOfStrings.push(item: "hate")
        stackOfStrings.push(item: "crazy")
        
        let newString = stackOfStrings.pop()
        print("newString = \(newString)")
        
        //创建Stack结构体,泛型类型为String
        var stackOfInt = Stack<Int>()
        stackOfInt.push(item: 11);
        stackOfInt.push(item: 22);
        stackOfInt.push(item: 33);
        stackOfInt.push(item: 44);
        stackOfInt.push(item: 55);

        let number = stackOfInt.pop()
        print("number = \(number)")

        /*********************泛型约束*********************/
        // 在浮点型数组中进行查找,Double默认遵循了Equatable协议
        let doubleIndex = findIndex(array: [3.14159, 0.1, 0.25], valueToFind: 9.3)
        //条件判断
        if let index = doubleIndex
        {
            print("在浮点型数组中寻找到9.3,寻找索引为\(index)")
        }
        else
        {
            print("在浮点型数组中寻找不到9.3")
        }
        
        // 在字符串数组中进行查找,String默认遵循了Equatable协议
        let stringIndex = findIndex(array: ["Mike", "Malcolm", "Andrea"], valueToFind: "Andrea")
        if let index = stringIndex
        {
            print("在字符串数组中寻找到Andrea,寻找索引为\(index)")
        }
        else
        {
            print("在字符串数组中寻找不到Andrea")
        }
        
        let newIndex = findArrayIndex(array: [100, 200], valueToFind: 200);
        if let index = newIndex
        {
            print(" 索引：index = \(index)")
        }
        
        /*********************关联泛型*********************/
        var stackOfStrings1 = genericStack<String>()
        stackOfStrings1.appended(item: "过年")
        stackOfStrings1.appended(item: "工作")
        stackOfStrings1.appended(item: "挣钱")
        
        let arrayOfStrings = ["过年", "工作", "挣钱"] //array类型的满足Container类型，参考上面的extension Array
        
        if allItemsMatch(someContainer: stackOfStrings1, arrayOfStrings)
        {
            print("All items match.")
        }
        else
        {
            print("Not all items match.")
        }
    }

   /*********************泛型函数*********************/
    //Swift的泛型
    func appendArray<T>(argu1: [T], argu2:inout [T])
    {
        for element in argu1
        {
            argu2.append(element)
        }
    }
    
    //交换值
    func swap<T>(oneValue:inout T, twoValue:inout T)
    {
        let tempValue = oneValue
        oneValue = twoValue
        twoValue = tempValue
    }
    /*********************泛型版本的栈*********************/
    struct Stack<T>
    {
        var items = [T]()
        mutating func push(item: T)
        {
            items.append(item)
        }
        
        mutating func pop() -> T
        {
            return items.removeLast()
        }
    }
    
    /*********************泛型约束*********************/
    //定义泛型函数,为泛型添加协议约束,泛型类型必须遵循Equatable协议
    func findIndex<T: Equatable> (array: [T], valueToFind: T) -> Int?
    {
        for (index,value) in array.enumerated()
        {
            if value == valueToFind
            {
                //因为遵循了Equatable协议,所以可以进行相等比较
                return index
            }
        }
        return nil
    }
    
    func findArrayIndex<S: Equatable> (array: [S], valueToFind: S) -> Int?
    {
        for (index,value) in array.enumerated()
        {
            if value == valueToFind
            {
                //因为遵循了Equatable协议,所以可以进行相等比较
                return index
            }
        }
        return nil
    }
    
    /*********************关联泛型*********************/
    struct genericStack<T>: Container
    {
        // genericStack<T> 的原始实现部分
        var items = [T]()
        mutating func push(item: T)
        {
            items.append(item)
        }
        mutating func pop() -> T
        {
            return items.removeLast()
        }
        //Container 协议的实现部分
        //这是设置关联类型具体是什么类型
        typealias itemType = T
        // Container 协议的实现部分
        mutating func appended(item: T)
        {
            self.push(item: item)
        }
        var count: Int
        {
            return items.count
        }
        subscript(i: Int) -> T
        {
            return items[i]
        }
    }

    func allItemsMatch<C1: Container,C2: Container>(someContainer: C1,_ anotherContainer: C2) -> Bool where C1.itemType == C2.itemType, C1.itemType: Equatable
    {
        if someContainer.count != anotherContainer.count
        {
            return false
        }
        for i in 0...someContainer.count-1
        {
            if someContainer[i] != anotherContainer[i]
            {
                return false
            }
        }
        return true
    }
    

}




